//********************************************************************************************
//
// File : arp.c implement for Address Resolution Protocol
//
//********************************************************************************************
//
// Copyright (C) 2007
//
// This program is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation; either version 2 of the License, or (at your option) any later
// version.
// This program is distributed in the hope that it will be useful, but
//
// WITHOUT ANY WARRANTY;
//
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the Free Software Foundation, Inc., 51
// Franklin St, Fifth Floor, Boston, MA 02110, USA
//
// http://www.gnu.de/gpl-ger.html
//
//********************************************************************************************
#include "enc28j60.h"
#include "ip.h"
#include "arp.h"
#include "StrLib.h"
//********************************************************************************************
//
// Address Resolution Protocol (ARP) is the method for finding a host's hardware address 
// when only its network layer address is known. 
// Due to the overwhelming prevalence of IPv4 and Ethernet, 
// ARP is primarily used to translate IP addresses to Ethernet MAC addresses. 
// It is also used for IP over other LAN technologies, 
// such as Token Ring, FDDI, or IEEE 802.11, and for IP over ATM.
//
// ARP is used in four cases of two hosts communicating:
// 
//   1. When two hosts are on the same network and one desires to send a packet to the other
//   2. When two hosts are on different networks and must use a gateway/router to reach the other host
//   3. When a router needs to forward a packet for one host through another router
//   4. When a router needs to forward a packet from one host to the destination host on the same network
//
// +------------+------------+-----------+
// + MAC header + ARP header +	Data ::: +
// +------------+------------+-----------+
// 
// ARP header
//
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// +00+01+02+03+04+05+06+07+08+09+10+11+12+13+14+15+16+17+18+19+20+21+22+23+24+25+26+27+28+29+30+31+
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// +             Hardware type 	                   +                    Protocol type              +
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// + HardwareAddressLength + ProtocolAddressLength +	                 Opcode                    +
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// +                                   Source hardware address :::                                 +
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// +                                   Source protocol address :::                                 +
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// +                                Destination hardware address :::                               +
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// +                                Destination protocol address :::                               +
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// +                                          Data :::                                             +
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
//
//********************************************************************************************

//********************************************************************************************
//
// Function : arp_generate_packet
// Description : generate arp packet
//
//********************************************************************************************
void cArp::GenerateArpPacket ( U8 *pBuff, U8 *pDestMac, U8 *pDestIP )
{
    // setup hardware type to ethernet 0x0001
    pBuff[ ARP_HARDWARE_TYPE_H_P ] = ARP_HARDWARE_TYPE_H_V;
    pBuff[ ARP_HARDWARE_TYPE_L_P ] = ARP_HARDWARE_TYPE_L_V;

    // setup protocol type to ip 0x0800
    pBuff[ ARP_PROTOCOL_H_P ] = ARP_PROTOCOL_H_V;
    pBuff[ ARP_PROTOCOL_L_P ] = ARP_PROTOCOL_L_V;

    // setup hardware length to 0x06
    pBuff[ ARP_HARDWARE_SIZE_P ] = ARP_HARDWARE_SIZE_V;

    // setup protocol length to 0x04
    pBuff[ ARP_PROTOCOL_SIZE_P ] = ARP_PROTOCOL_SIZE_V;

    // setup arp destination and source mac address
    cStrLib::Strcpy(&pBuff[ ARP_DST_MAC_P ], pDestMac, cIP::MAC_ADDR_LEN);
    cStrLib::Strcpy(&pBuff[ ARP_SRC_MAC_P ], cIP::GetMacAddr(), cIP::MAC_ADDR_LEN);

    // setup arp destination and source ip address
    cStrLib::Strcpy(&pBuff[ ARP_DST_IP_P ], pDestIP, cIP::IP_ADDR_LEN);
    cStrLib::Strcpy(&pBuff[ ARP_SRC_IP_P ], cIP::GetIPAddr(), cIP::IP_ADDR_LEN);
}
//********************************************************************************************
//
// Function : arp_send_request
// Description : send arp request packet (who is?) to network.
//
//********************************************************************************************
//void cArp::arp_send_request ( U8 *rxtx_buffer, U8 *dest_ip )
//{
//    U8 i;
//    cEthernet::MAC_ADDR dest_mac;
//
//    // generate ethernet header
//    for ( i=0; i<sizeof(cEthernet::MAC_ADDR); i++)
//        dest_mac.byte[i] = 0xff;
//    cIP::GenerateMacHeader ( rxtx_buffer, cIP::MAC_TYPE_ARP_VAL, (U8*)&dest_mac );
//
//    // generate arp packet
//    for ( i=0; i<sizeof(cEthernet::MAC_ADDR); i++)
//        dest_mac.byte[i] = 0x00;
//
//    // set arp opcode is request
//    rxtx_buffer[ ARP_OPCODE_H_P ] = ARP_OPCODE_REQUEST_H_V;
//    rxtx_buffer[ ARP_OPCODE_L_P ] = ARP_OPCODE_REQUEST_L_V;
//    arp_generate_packet ( rxtx_buffer, (U8*)&dest_mac, dest_ip );
//
//    // send arp packet to network
//    cEnc28j60::enc28j60_packet_send ( rxtx_buffer, sizeof(cEthernet::ETH_HEADER) + sizeof(cEthernet::ARP_PACKET) );
//}
//*******************************************************************************************
//
// Function : arp_packet_is_arp
// Description : check received packet, that packet is match with arp and avr ip or not?
//
//*******************************************************************************************
bool cArp::IsArpPacket ( U8 *pBuff, U16 iOpcode )
{
    // if packet type is not arp packet exit from function
    if( pBuff[ cIP::MAC_TYPE_H_POS ] != cIP::MAC_TYPE_ARP_H_VAL || pBuff[ cIP::MAC_TYPE_L_POS ] != cIP::MAC_TYPE_ARP_L_VAL)
    {
        return (false);
    }
    // check arp request opcode
    if ( pBuff[ ARP_OPCODE_H_P ] != cStrLib::GetHigh16(iOpcode) || pBuff[ ARP_OPCODE_L_P ] != cStrLib::GetLow16(iOpcode) )
    {
        return (false);
    }
    // if destination ip address in arp packet not match with avr ip address
    return (cIP::IPCmp(&pBuff[ARP_DST_IP_P]));
}
//*******************************************************************************************
//
// Function : arp_send_reply
// Description : Send reply if recieved packet is ARP and IP address is match with avr_ip
//
//*******************************************************************************************
void cArp::SendReply ( U8 *pBuff, U8 *pDestMac )
{
    // generate ethernet header
    cIP::GenerateMacHeader ( pBuff, cIP::MAC_TYPE_ARP_VAL, pDestMac );

    // change packet type to echo reply
    pBuff[ ARP_OPCODE_H_P ] = ARP_OPCODE_REPLY_H_V;
    pBuff[ ARP_OPCODE_L_P ] = ARP_OPCODE_REPLY_L_V;
    GenerateArpPacket ( pBuff, pDestMac, &pBuff[ ARP_SRC_IP_P ] );

    // send arp packet
    cEnc28j60::SendPacket ( pBuff, cIP::MAC_HEADER_LEN + sizeof(cIP::ARP_PACKET) );
}
